package cn.csg.ams.collect2.poptopics.task;

import cn.csg.ams.collect2.poptopics.dao.MkMcTermAlarmLogDao;
import cn.csg.ams.collect2.poptopics.dao.MkPrPfOutageRecoveryMonDao;
import cn.csg.ams.collect2.poptopics.entity.vo.MkPrPfOutageRecoveryMonVO;
import cn.csg.ams.collect2.poptopics.infrastructure.constant.UserCategoryConstant;
import cn.csg.ams.collect2.poptopics.infrastructure.utils.RedisLockUtil;
import cn.csg.ams.collect2.poptopics.redisPool.OutagePool;
import cn.csg.ams.collect2.poptopics.service.MkPrPfOutageRecoveryMonService;
import cn.hutool.core.map.MapUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 线路停电任务，每15分钟执行一次
 */
@Component
public class LineOutageTask {

    private static Logger logger = LoggerFactory.getLogger(LineOutageTask.class);


    @Autowired
    private OutagePool outagePool;

    @Autowired
    private MkMcTermAlarmLogDao alarmLogDao;

    @Autowired
    private MkPrPfOutageRecoveryMonDao outageRecoveryMonDao;

    @Autowired
    private MkPrPfOutageRecoveryMonService recoveryMonService;

    @Autowired
    private RedisLockUtil redisLockUtil;


    @Scheduled(cron = "0 0/15 * * * ?")
    public void lineOutageTask() {
        // 由于多节点部署，需要保证每次只有一个节点执行
        String key = "fbs_line_outage";
        String requestId = UUID.randomUUID().toString();
        boolean lock = redisLockUtil.lock(key, requestId, 120 * 1000);
        if (!lock) {
            logger.info("该节点未抢到锁，跳过线路停电任务");
            return;
        }

        // 执行线路停电任务
        logger.info("节点抢到锁, 开始执行线路停电任务.............");
        lineOutage();
    }


    private void lineOutage() {
        int dataPart = Integer.parseInt(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        long startTimes = System.currentTimeMillis();

        // 查询近15分钟最新的线路考核户电表的电流为0的线路
        List<Map<String, Object>> lineList = alarmLogDao.curDipLine(dataPart);

        for (Map<String, Object> map : lineList) {
            // 地区编码
            String areaCode = MapUtil.getStr(map, "area_code");
            // 线路编号
            String lineNo = MapUtil.getStr(map, "line_no");
            // 电流骤降为0的时间
            String outageSatrtTime = MapUtil.getStr(map, "data_time");
            // 电流骤降为0的前置接收时间
            String preReceTime = MapUtil.getStr(map, "pre_rece_time");

            // 查询线路是否已经停电
            if (outagePool.getLineOutage(lineNo, areaCode) != null) {
                return;
            }

            // 查询线路下影响的所有对象
            List<String> userTypes = Arrays.asList(UserCategoryConstant.LINE, UserCategoryConstant.PUBLIC_TA, UserCategoryConstant.SPECIALTY_TA, UserCategoryConstant.SPECIALTY_TA2, UserCategoryConstant.BRANCH, UserCategoryConstant.LOW_USER);
            List<MkPrPfOutageRecoveryMonVO> list = outageRecoveryMonDao.queryList(areaCode, lineNo, null, null, null, userTypes);
            // 设置研判规则
            list.forEach(vo -> vo.setJudgeRule("ZDGZ1-10"));

            // 停电事件id
            String eventId = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + lineNo;

            // 记录线路停电
            outagePool.saveTaOutageToLine(lineNo, areaCode, lineNo, outageSatrtTime);
            String[] values = list.stream().filter(vo -> UserCategoryConstant.LINE.equals(vo.getObjType())).map(o -> areaCode + "-" + o.getRunMeterId()).toArray(String[]::new);
            outagePool.addOutageSet(values);

            // 保存数据到 '实时停复电监测'
            recoveryMonService.saveRecoveryByLeafList(list, outageSatrtTime, preReceTime, eventId, startTimes, startTimes);

            // 将数据按台区分组
            Map<String, List<MkPrPfOutageRecoveryMonVO>> taDataMap = list.stream()
                    .collect(Collectors.groupingBy(vo -> vo.getTaNo() + "-" + vo.getAreaCode()));

            // 将所有停电数据添加到停电池中
            taDataMap.forEach((taNoAndAreaCode, taDataList) -> {
                String[] split = taNoAndAreaCode.split("-");
                outagePool.putOutageInfoToRedis(taDataList, outageSatrtTime, split[0], split[1]);
            });
        }
    }
}
